package com.ayf.payment.game.api.task.patchpay;

import com.ayf.payment.game.api.dto.MerchantPayOrderDTO;
import com.ayf.payment.game.api.service.MerchantPayOrderService;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.github.pagehelper.PageHelper;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @Author: zh-liang
 * @Date : 2020-05-28
 */
@Component
public abstract class BatchPayTaskBasic {

    @Autowired
    private MerchantPayOrderService merchantPayOrderService;

    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String traceId = SnowFlakeUtils.getUniqueId();
        String lockName = "BatchPayTaskBasic-"+this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        try {
            if (lock = distributedLock.getLock(lockName)) {
                LogPortal.info("[{}] get lock and run [{}] ", traceId, lockName);

                PageHelper.startPage(1, 200);
                List<MerchantPayOrderDTO> merchantPayOrders = merchantPayOrderService.selectBatchPayInfo(0);

                LogPortal.info("[{}][{}]批量代付定时发起代付开始执行，本次执行处理的的代付订单数量为[{}]", traceId, lockName, merchantPayOrders.size());
                //初始化信号
                final CountDownLatch countDownLatch = new CountDownLatch(merchantPayOrders.size());
                for (int i = 0; i < merchantPayOrders.size(); i++) {
                    int count = i + 1;
                    MerchantPayOrderDTO payOrder = merchantPayOrders.get(i);
                    submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                //睡1秒
                                Thread.sleep(1000);
                                boolean boo = merchantPayOrderService.createBathPayOrder(payOrder);
                                if (boo) {
                                    LogPortal.info("[{}]第[{}]笔代付发起成功,代付批次号为[{}],订单号为[{}]", traceId, count, payOrder.getBatchNo(),
                                            payOrder.getMerchantOrderNo());
                                }else {
                                    LogPortal.error("[{}]第[{}]笔代付发起失败,代付批次号为[{}],订单号为[{}]", traceId, count,
                                            payOrder.getBatchNo(),
                                            payOrder.getMerchantOrderNo());
                                }
                            } catch (Exception e) {
                                LogPortal.error("[{}]第[{}]笔代付发起失败,代付批次号为[{}],订单号为[{}]", traceId, count, payOrder.getBatchNo(),
                                        payOrder.getMerchantOrderNo());
                            } finally {
                                //线程执行完成之后标记信号表示完成
                                countDownLatch.countDown();
                            }
                        }
                    });
                }
                LogPortal.info("[{}][{}]批量代付定时发起代付执行完成，本次执行处理的的代付订单数量为[{}]", traceId, lockName,
                        merchantPayOrders.size());
                //等待线程池任务执行完毕
                countDownLatch.await();
            } else {
                LogPortal.info("[{}][{}]do not get lock ", traceId, lockName);
            }
        } catch (GetLockFailedException e) {
            LogPortal.error("[{}][DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("[{}][{}]获取lock失败", e, traceId, lockName);
        } catch (Exception e) {
            LogPortal.error("[{}][{}]任务执行出错 ", e, traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info("[{}][{}]finished.", traceId, lockName);
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("[{}][DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("[{}][{}]释放失败", e, traceId, lockName);
                }
            }
        }
    }

    public abstract void submit(Runnable task);

}
